<template>
  <div class="grid-layout">
    <div v-if="title || $slots.title" class="grid-layout-title">
      <slot name="title">{{ title }}</slot>
    </div>
    <div
      class="grid-layout-row"
      :style="{ display: 'grid', gridTemplateColumns: gridCols, gridGap: gridGap, overflow: 'hidden' }"
    >
      <div class="grid-layout-col" v-for="item of options" :key="item.name" :style="colStyle(item)">
        <slot :name="item.name" />
      </div>
    </div>
    <div v-if="bottom || $slots.bottom" class="grid-layout-bottom">
      <slot name="bottom">{{ bottom }}</slot>
    </div>
  </div>
</template>

<script>
const flexStyle = {
  display: 'flex',
  flexDirection: 'column',
  flexWrap: 'nowrap',
  justifyContent: 'flex-start',
};

export default {
  name: 'grid-layout',
  props: {
    layout: {
      type: Array,
      default: () => [
        { name: 'left', colSpan: 8 },
        { name: 'right', colSpan: 16 },
      ],
    },
    title: { type: String, default: '' },
    bottom: { type: String, default: '' },
    gutter: { type: [Number, String], default: 0 },
    useFlex: { type: Boolean, default: true },
    itemStyle: { type: Object, default: undefined },
  },
  computed: {
    options() {
      return this.layout.reduce((res, item) => {
        let colSpan = item.colSpan;
        if (colSpan && typeof colSpan === 'object') {
          colSpan = colSpan.span;
        }
        if (!Number.isFinite(colSpan)) {
          return res;
        }
        res.push(Object.assign({}, item, { colSpan }));
        return res;
      }, []);
    },
    gridCols() {
      return this.options.map(({ colSpan }) => (colSpan / 24) * 100 + '%').join(' ');
    },
    gridGap() {
      return typeof this.gutter === 'string' ? this.gutter : this.gutter + 'px';
    },
    colStyle() {
      return (item) => {
        if (!item || typeof item !== 'object') {
          return {};
        }
        let { style, useFlex } = item;
        style = Object.assign({}, this.itemStyle, style);
        useFlex = typeof useFlex === 'boolean' ? useFlex : this.useFlex;
        return useFlex === true ? Object.assign({}, flexStyle, style) : style;
      };
    },
  },
};
</script>

<style lang="less">
.grid-layout {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: flex-start;
  width: 100%;
  height: 100%;
  text-align: left;

  .grid-layout-title,
  .grid-layout-bottom {
    width: 100%;
    box-sizing: border-box;
    flex: none;
    padding: 10px 20px;
    font-size: 26px;
    font-weight: 500;
    color: var(--font-color-1, #fefefe);
  }
  .grid-layout-title {
    border-bottom: 1px solid var(--border-color-1, #e8e8e8);
  }
  .grid-layout-bottom {
    border-top: 1px solid var(--border-color-1, #e8e8e8);
  }
  .grid-layout-row {
    flex: auto;
    height: auto;
    min-height: 0;
    overflow: hidden;
    width: 100%;
    .grid-layout-col {
      box-sizing: border-box;
      height: 100%;
      overflow: hidden auto;
      &:not(:first-child) {
        border-left: 1px solid var(--border-color-1, #e8e8e8);
      }
    }
  }
}
</style>
